#-*- coding: utf-8 -*-

import xmlrpclib
import os.path
import hashlib
from bottle import get, post, route, request, response
from bottle import jinja2_view as jview
from auth import CookieUser
from blog import *
from config import host_name
from utils import to_time, now

class XMLRPCDispatcher(object):
	def __init__(self):
		self.methods = {}

	def register_function(self, method_name, handler):
		if method_name not in self.methods.keys():
			if callable(handler):
				self.methods[method_name] = handler

	def make_call(self, method_call):
		method_name = method_call['methodName']
		handler = self.methods.get(method_name)
		if handler:
			result = handler(*method_call['params'])
			return result
		return None

def get_user_blogs(blogid, username, password):
	service = BlogService()
	blog = service.get_blog(userid=blogid) if blogid and blogid.isdigit() else service.get_blog(username=username)
	if blog.exists():
		bloguser = blog.get_owner()
		return [{
			'url':'http://%s/user/%s/' % (host_name, bloguser.id), 
			'blogid': '%s' % bloguser.id, 
			'blogName':bloguser.namealias
		}]
	else:
		return []

def get_user_categories(blogid, username, password):
	service = BlogService()
	blog = service.get_blog(userid=blogid) if blogid and blogid.isdigit() else service.get_blog(username=username)
	if blog.exists():
		categories = blog.get_categories()
		return [{'title':c.categoryname, 'description':''} for c in categories]
	else:
		return []

def create_new_post(blogid, username, password, post, publish_rightnow):
	auth_success, bloguser = BlogUser.authenticate(username, password)
	if auth_success:
		blog = bloguser.get_blog()
		new_post = Post()
		new_post.userid = bloguser.id
		new_post.subject = post['title']
		new_post.subjecturl = ''
		new_post.frontphoto = ''
		new_post.content = post['description']
		new_post.createdate = to_time(now())
		new_post.status = 10 if publish_rightnow else 0
		new_post.categoryid = 0
		categories = post['categories']
		categoryname = categories[0] if categories else None
		if categoryname:
			category = blog.get_category_by_name(categoryname)
			if category:
				new_post.categoryid = category.id
		new_post.commentcount = 0
		new_post.lastmodified = new_post.createdate
		new_post.allowcomment = True
		new_post.highlight = False
		new_post.upvote = 0
		new_post.downvote = 0
		new_post.save()
		if new_post.id:
			return new_post.id
		else:
			raise Exception('Failed to save the new post.')
	else:
		raise Exception('Failed to authenticate.')


def update_exists_post(postid, username, password, post, publish_rightnow):
	auth_success, bloguser = BlogUser.authenticate(username, password)
	if auth_success:
		blog = bloguser.get_blog()
		target_post = blog.get_post(postid=postid)
		if not target_post:
			raise Exception('The post was not found.')
		# target_post.userid = bloguser.id
		target_post.subject = post['title']
		# target_post.subjecturl = ''
		# target_post.frontphoto = ''
		target_post.content = post['description']
		# target_post.createdate = to_time(now())
		target_post.status = 10 if publish_rightnow else 0
		target_post.categoryid = 0
		categories = post['categories']
		categoryname = categories[0] if categories else None
		if categoryname:
			category = blog.get_category_by_name(categoryname)
			if category:
				target_post.categoryid = category.id
		# target_post.commentcount = 0
		target_post.lastmodified = to_time(now())
		# target_post.allowcomment = True
		# target_post.highlight = False
		# target_post.upvote = 0
		# target_post.downvote = 0
		target_post.save()
		return True
	else:
		raise Exception('Failed to authenticate.')

def get_user_recent_posts(blogid, username, password, num_posts):
	auth_success, bloguser = BlogUser.authenticate(username, password)
	if auth_success:
		blog = bloguser.get_blog()
		posts, more_items = blog.get_posts(page=1, pagesize=num_posts if num_posts>0 else 7, only_published=False) 
		return [{
			'postid': '%s' % p.id, 
			'dateCreated': p.createdate_dt, 
			'title': p.subject, 
			'description': p.content, 
			'categories': [c.categoryname for c in p.categories], 
			'publish': p.published
		} for p in posts]
	else:
		raise Exception('Failed to authenticate.')

def get_user_single_post(postid, username, password):
	auth_success, bloguser = BlogUser.authenticate(username, password)
	if auth_success:
		blog = bloguser.get_blog()
		target_post = blog.get_post(postid=postid)
		if not target_post:
			raise Exception('The post was not found.')
		return {
			'postid':'%s' % target_post.id, 
			'dateCreated': target_post.createdate_dt, 
			'title': target_post.subject, 
			'description': target_post.content, 
			'categories': [c.categoryname for c in target_post.categories], 
			'publish': target_post.published
		}
	else:
		raise Exception('Failed to authenticate.')


def delete_user_post(appKey, postid, username, password, publish):
	auth_success, bloguser = BlogUser.authenticate(username, password)
	if auth_success:
		blog = bloguser.get_blog()
		target_post = blog.get_post(postid=postid)
		if not target_post:
			raise Exception('The post was not found.')
		target_post.delete()
		return True
	else:
		raise Exception('Failed to authenticate.')


def upload_media_file(blogid, username, password, mediadata):
	auth_success, bloguser = BlogUser.authenticate(username, password)
	if auth_success:
		blog = bloguser.get_blog()
		mediatype = mediadata['type']
		filedata = mediadata['bits']
		original_name = os.path.basename(mediadata['name'])
		ext = os.path.splitext(original_name)[1].lower()
		supported_filetypes = ('.jpg', '.gif', '.png', '.bmp', '.jpeg', '.jpe',
			'.mp3', '.wma', '.wmv', '.swf', '.mp4', '.mov')
		if ext not in supported_filetypes:
			raise Exception('You can only upload %s files.' % ', '.join(supported_filetypes))
		local_filename = '%s_rpc_upload%s' % (hashlib.md5(filedata.data).hexdigest(), ext)
		f = open('static/media/%s' % local_filename, 'wb+')
		f.write(filedata.data)
		f.close()
		return {'url':'http://%s/static/media/%s' % (host_name, local_filename)}
	else:
		raise Exception('Failed to authenticate.')


@get('/xmlrpc/')
@get('/xmlrpc')
@post('/xmlrpc/')
@post('/xmlrpc')
def xmlrpc_handler():
	response.headers['content-type'] = 'text/xml'
	req_data = request.body.read() if request.body else ''
	if req_data:
		args, method_name = xmlrpclib.loads(req_data)
		faultMsg = ''
		try:
			dispatcher = XMLRPCDispatcher()
			dispatcher.register_function('metaWeblog.getCategories', get_user_categories)
			dispatcher.register_function('metaWeblog.getRecentPosts', get_user_recent_posts)
			dispatcher.register_function('metaWeblog.newPost', create_new_post)
			dispatcher.register_function('metaWeblog.editPost', update_exists_post)
			dispatcher.register_function('metaWeblog.getPost', get_user_single_post)
			dispatcher.register_function('metaWeblog.newMediaObject', upload_media_file)
			dispatcher.register_function('blogger.getUsersBlogs', get_user_blogs)
			dispatcher.register_function('blogger.deletePost', delete_user_post)
			method_call = {
				'methodName': method_name,
				'params': args
			}	
			results = dispatcher.make_call(method_call)
			if results is None:
				faultMsg = u'Unsupported method "%s".' % method_name
			else:
				results = xmlrpclib.dumps((results,), methodresponse=True, allow_none=True)
				return results
		except Exception, e:
			faultMsg = u'Error occured when processing: %s' % e
		fault = xmlrpclib.Fault(1, faultMsg) if faultMsg else None
		if fault:
			return xmlrpclib.dumps(fault, methodresponse=True)
	else:
		fault = xmlrpclib.Fault(1, u'Empty request.')
		return xmlrpclib.dumps(fault, methodresponse=True)


